package com.zwh.common.bean;

import com.zwh.common.bean.annotation.BeanLog;
import com.zwh.common.bean.annotation.BeanLogs;
import com.zwh.common.reflect.ReflectUtils;


import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 操作日志比对工具类
 * @Author zwh
 * @Date 2019/10/21 17:02
 **/
public class OperationLogUtil {
    private static final List<Class<?>> WRAPPER = Arrays.asList(Byte.class, Short.class,
            Integer.class, Long.class, Float.class, Double.class, Character.class,
            Boolean.class, String.class);

    /**
     * 采用反射进行比较。将新数据和旧数据进行指定属性值的比较
	 * 返回发生变化的属性值列表。
     * 限制条件：
     * 1、需要在实体类中的字段加入注解
     * 3、注解只能加在定义为单一类型的字段上。不能在List、关联关系对象上进行加入
     *
     * @param newData
     * @param oldData
     * @return
     * @throws Exception
     */
    public <T> List<FieldInfo> getOperateLog(T newData, T oldData, String... groups) {
        //获取需要对比的属性列表
        List<Object[]> annotationList = new ArrayList<>();
        List<FieldInfo> fieldInfoList = new ArrayList<>();
        Class<? extends Object> clazz = newData.getClass();
        // 获取自己声明的各种字段，包括public，protected，private。不包括父类的申明字段
        // getFields()只能获取public的字段，包括父类的。请自行区别
        Field[] reflectFields = clazz.getDeclaredFields();
        for (Field field : reflectFields) {
            BeanLogs beanLogs = field.getAnnotation(BeanLogs.class);
            if (beanLogs != null && beanLogs.value() != null) {
                for (BeanLog ef : beanLogs.value()) {
                    addAnnotation(annotationList, ef, field, groups);
                }
            }
            BeanLog beanLog = field.getAnnotation(BeanLog.class);
            addAnnotation(annotationList, beanLog, field, groups);
        }
        // Get annotation method
        Method[] ms = clazz.getDeclaredMethods();
        for (Method m : ms) {
            BeanLogs beanLogs = m.getAnnotation(BeanLogs.class);
            if (beanLogs != null && beanLogs.value() != null) {
                for (BeanLog ef : beanLogs.value()) {
                    addAnnotation(annotationList, ef, m, groups);
                }
            }
            BeanLog beanLog = m.getAnnotation(BeanLog.class);
            addAnnotation(annotationList, beanLog, m, groups);
        }

        for (Object[] os : annotationList) {
            BeanLog beanLog = (BeanLog) os[0];
            Object newVal = null;
            Object oldVal = null;
            // Get entity value
            try {
                if (beanLog.attrName()!=null&&beanLog.attrName()!="") {
                    newVal = ReflectUtils.invokeGetter(newData, beanLog.attrName());
                    oldVal = ReflectUtils.invokeGetter(oldData, beanLog.attrName());
                } else {
                    continue;
                }
            } catch (Exception ex) {
                // Failure to ignore
                ex.printStackTrace();
//                log.info(ex.toString());
            }
            String pattern = beanLog.dataFormat();
            if (pattern.equals("@")) {
                pattern = "yyyy-MM-dd HH:mm:ss";
            }
            if (!compareSimpleField(newVal, oldVal,pattern)) {
                //不相等
                FieldInfo fieldInfo = new FieldInfo();
                fieldInfo.setFieldName(beanLog.title());
                //新旧数据其中一个为日期，则处理日期
                if (newVal instanceof Date||oldVal instanceof Date) {
                    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                    fieldInfo.setNewVal(newVal==null?"":sdf.format(newVal).toString());
                    fieldInfo.setOldVal(oldVal==null?"":sdf.format(oldVal).toString());
                } else {
                    fieldInfo.setNewVal(newVal);
                    fieldInfo.setOldVal(oldVal);
                }

                fieldInfoList.add(fieldInfo);
            }

        }
        return fieldInfoList;

    }

    /**
     *
     * @param newData
     * @param oldData
     * @param annotationList 对比的属性列表注解
     * @param groups
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> List<FieldInfo> getOperateLog(T newData, T oldData,List<Object[]> annotationList, String... groups) throws Exception {
        List<FieldInfo> fieldInfoList = new ArrayList<>();
        //需要对比的属性列表
        for (Object[] os : annotationList) {
            BeanLog beanLog = (BeanLog) os[0];
            Object newVal = null;
            Object oldVal = null;
            // Get entity value
            try {
                if (beanLog.attrName()!=null&&beanLog.attrName()!="") {
                    newVal = ReflectUtils.invokeGetter(newData, beanLog.attrName());
                    oldVal = ReflectUtils.invokeGetter(oldData, beanLog.attrName());
                } else {
                    continue;
                }
            } catch (Exception ex) {
                // Failure to ignore
                ex.printStackTrace();
//                log.info(ex.toString());
            }
            String pattern = beanLog.dataFormat();
            if (pattern.equals("@")) {
                pattern = "yyyy-MM-dd HH:mm:ss";
            }
            if (!compareSimpleField(newVal, oldVal,pattern)) {
                //不相等
                FieldInfo fieldInfo = new FieldInfo();
                fieldInfo.setFieldName(beanLog.title());
                if (newVal instanceof Date||oldVal instanceof Date) {
                    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                    fieldInfo.setNewVal(newVal==null?"":sdf.format(newVal).toString());
                    fieldInfo.setOldVal(oldVal==null?"":sdf.format(oldVal).toString());
                } else {
                    fieldInfo.setNewVal(newVal);
                    fieldInfo.setOldVal(oldVal);
                }

                fieldInfoList.add(fieldInfo);
            }

        }
        return fieldInfoList;

    }

    public List<Object[]> getAnnotationList(Class<? extends Object> clazz,String... groups){
        //获取需要对比的属性列表
        List<Object[]> annotationList = new ArrayList<>();
        // 获取自己声明的各种字段，包括public，protected，private。不包括父类的申明字段
        // getFields()只能获取public的字段，包括父类的。请自行区别
        Field[] reflectFields = clazz.getDeclaredFields();
        for (Field field : reflectFields) {
            BeanLogs beanLogs = field.getAnnotation(BeanLogs.class);
            if (beanLogs != null && beanLogs.value() != null) {
                for (BeanLog ef : beanLogs.value()) {
                    addAnnotation(annotationList, ef, field, groups);
                }
            }
            BeanLog beanLog = field.getAnnotation(BeanLog.class);
            addAnnotation(annotationList, beanLog, field, groups);
        }
        // Get annotation method
        Method[] ms = clazz.getDeclaredMethods();
        for (Method m : ms) {
            BeanLogs beanLogs = m.getAnnotation(BeanLogs.class);
            if (beanLogs != null && beanLogs.value() != null) {
                for (BeanLog ef : beanLogs.value()) {
                    addAnnotation(annotationList, ef, m, groups);
                }
            }
            BeanLog beanLog = m.getAnnotation(BeanLog.class);
            addAnnotation(annotationList, beanLog, m, groups);
        }

        return annotationList;
    }

    /**
     * 基本数据类型及其包装类型的数据比较：八大基本数据类型及包装类，及String和Date
     * 如果不满足基本类型的数据要求，默认返回为true
     *
     * @param newObject
     * @param oldObject
     * @param pattern
     * @return true 相等，false不相等
     */
    public boolean compareSimpleField(Object newObject, Object oldObject, String... pattern) {
        if (newObject == null && oldObject == null) {
            return true;
        }
        if (newObject == null && oldObject != null) {
            return false;
        }
        if (newObject != null && oldObject == null) {
            return false;
        }

        //数值类型处理
        if (newObject instanceof Number) {
            return newObject.equals(oldObject);
        }

        if (newObject instanceof String) {
            return newObject.equals(oldObject);
        }
        if (newObject instanceof Date) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern[0]);
            return sdf.format(newObject).toString().equals(sdf.format(oldObject).toString());
        }
        if (newObject instanceof Boolean) {
            return newObject.equals(oldObject);
        }

        return true;
    }


    /**
     * 判断是否为原始数据类型
     * 包括String字符串对象
     *
     * @param field 对象
     * @return 是否为原始数据类型
     */
    boolean isSimpleField(Object field) {
        Class<?> clazz = field.getClass();
        return clazz.isPrimitive() || WRAPPER.contains(clazz);
    }

    /**
     * 添加到 annotationList
     */
    private void addAnnotation(List<Object[]> annotationList, BeanLog ef, Object fOrM, String... groups) {
//		if (ef != null && (ef.type()==0 || ef.type()==type)){
        if (ef != null) {
            if (groups != null && groups.length > 0) {
                boolean inGroup = false;
                for (String g : groups) {
                    if (inGroup) {
                        break;
                    }
                    for (String efg : ef.groups()) {
                        //属于同一组，加入到注解中
                        if (g.equals(efg)) {
                            inGroup = true;
                            annotationList.add(new Object[]{ef, fOrM});
                            break;
                        }
                    }
                }
            } else {
                annotationList.add(new Object[]{ef, fOrM});
            }
        }
    }


}
